package com.vinjogames.util;

import android.app.Activity;
import android.graphics.PointF;
import android.os.Handler;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;

import com.vinjogames.gfx.Camera;
import com.vinjogames.gfx.GameRenderer;
import com.vinjogames.som.entities.Game;

public class InputManager {

	private ScaleGestureDetector mScaleGD;
	private Camera mCamera;
	private Game mGame;
	
	private float downX;
	private float downY;

	private float moveX;
	private float moveY;
	PointF GLLocation;
	PointF WorldLocation;
	PointF ScreenLocation;
	PointF tempPointF;
	
	public static final int INPUT_TAP = 0;
	public static final int INPUT_DOWN = 1;
	public static final int INPUT_UP = 2;
	public static final int INPUT_DRAG = 3;
	public static final int INPUT_ZOOM = 4;
	public static final int INPUT_MENU = 5;
	

	
	private InputManager(){};

	private static class InputManagerHolder {
		public static final InputManager instance = new InputManager();
	}

	public static InputManager getInstance(){
		return InputManagerHolder.instance;
	}
	
	public void init(Activity mActivity, Game game){
		mGame = game;
		mScaleGD = new ScaleGestureDetector(mActivity, new ScaleListener());
		mCamera = Camera.getInstance();
		downX = -1;
		downY = -1;

		moveX = -1;
		moveY = -1;

		GLLocation = new PointF();
		WorldLocation = new PointF();
		ScreenLocation = new PointF();
		tempPointF = new PointF();
	}
	
	public void handleTouchEvent(MotionEvent e) throws Exception{
		if(!GameRenderer.renderStarted() || GameRenderer.isLoading()) return;
		
		mScaleGD.onTouchEvent(e);
		ScreenLocation.set(e.getX(), e.getY());
		WorldLocation.set(mCamera.getWorldX(e.getX()), mCamera.getWorldY(e.getY()));
		GLLocation.set(mCamera.getGLX(e.getX()), mCamera.getGLY(e.getY()));

		switch(e.getAction() & MotionEvent.ACTION_MASK){
		//Another finger is detected.
		case MotionEvent.ACTION_POINTER_DOWN:
			// If true, probably means we want to zoom (in this implementation)
			break;
		case MotionEvent.ACTION_DOWN:
			if(downX < 0){ //&& startY < 0){
				downX = e.getX();
				downY = e.getY();
			}
			handler.post(downLoop);
			break;
		case MotionEvent.ACTION_POINTER_UP:
		case MotionEvent.ACTION_UP:
			handler.removeCallbacks(downLoop);

			sendAction(INPUT_UP, ScreenLocation, 0);
			downX = -1;
			downY = -1;
			moveX = -1;
			moveY = -1;
			break;
		case MotionEvent.ACTION_MOVE:
			//Logger.log("[InputManager]: Move");
			if(moveX >= 0) {			
				if(!mScaleGD.isInProgress()) {		
					WorldLocation.set(WorldLocation.x - mCamera.getWorldX(moveX), WorldLocation.y - mCamera.getWorldY(moveY));
					sendAction(INPUT_DRAG,WorldLocation, 0);
				}
			}
			moveX = e.getX();
			moveY = e.getY();
			break;
		}
	}
	
	public void sendAction(int action, PointF location, float scale) throws Exception{
		switch(action){
		case INPUT_TAP:
			Logger.log("Tap: Pixel  x: " + location.x + " y: " + location.y);
			Logger.log("Screen x: " + GLLocation.x + " y: " + GLLocation.y);
			Logger.log("World  x: " + WorldLocation.x + " y: " + WorldLocation.y);
			break;
		case INPUT_UP:
			Logger.log("Up: Pixel  x: " + location.x + " y: " + location.y);
			mGame.handleUp(location);
			break;
		case INPUT_DOWN:
			Logger.log("Down: Pixel  x: " + location.x + " y: " + location.y);
			mGame.handleTouch(location);
			break;
		case INPUT_DRAG:
			// Moved to GUI
			//Location here is actually delta x,y
			/*if(location.x >0){
				if(location.y >0){
					Logger.log("Dragging up right");
					if(Math.abs(location.x) > Math.abs(location.y)){
						mGame.getPlayer().state = 3;
					}else{
						mGame.getPlayer().state = 1;
					}
					
				}else{
					Logger.log("Dragging down right");
					
					if(Math.abs(location.x) > Math.abs(location.y)){
						mGame.getPlayer().state = 3;
					}else{
						mGame.getPlayer().state = 0;
					}
				}
			}else{
				if(location.y >0){
					Logger.log("Dragging up left");
					if(Math.abs(location.x) > Math.abs(location.y)){
						mGame.getPlayer().state = 2;
					}else{
						mGame.getPlayer().state = 1;
					}
				}else{
					Logger.log("Dragging down left");
					if(Math.abs(location.x) > Math.abs(location.y)){
						mGame.getPlayer().state = 2;
					}else{
						mGame.getPlayer().state = 0;
					}
				}
			}
			*/
			mGame.handleDrag(location);
			
			break;
		case INPUT_ZOOM:
			mCamera.zoom(scale, location);
			break;
		case INPUT_MENU:
			Logger.log("[InputManager] - Menu pressed!");
			break;

		}
	}
	
	private Handler handler = new Handler();
	private Runnable downLoop = new Runnable(){
		@Override
		public void run() {
			tempPointF.set(downX,downY);
			try {
				sendAction(INPUT_DOWN, tempPointF,0);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			handler.postDelayed(downLoop, 100);//Send every 100ms
		}
	};
	
	private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener{
		@Override
		public boolean onScale(ScaleGestureDetector detector){
			tempPointF.set(detector.getFocusX(),detector.getFocusY());
			try {
				sendAction(INPUT_ZOOM, tempPointF,detector.getScaleFactor() );
			} catch (Exception e) {
				e.printStackTrace();
			}
			return true;
		}
	}
}
